#include "MediaTcpClient.h"
#include "MsgQueueManage.h"
#include <log.h>
#include <iostream>
#include <cstring>
#include "CurtainActManager.h"


namespace Media{

std::map<std::string, MediaTcpClient *>   MediaTcpClient::sm_objectMap;
std::recursive_mutex 		              MediaTcpClient::sm_mapMutex;


MediaTcpClient *MediaTcpClient::instance(std::string svrAddr)
{
    std::lock_guard<std::recursive_mutex> guard(sm_mapMutex);
    
	if(sm_objectMap.find(svrAddr) == sm_objectMap.end())
	{
		sm_objectMap[svrAddr] = new MediaTcpClient(svrAddr);
	}

	return sm_objectMap[svrAddr];
}


MediaTcpClient::MediaTcpClient(std::string svrAddr) 
{   
    m_svrAddr = svrAddr;
}

MediaTcpClient::~MediaTcpClient() 
{   
    if(m_clientSockfd > 0)
    {
        close(m_clientSockfd);
    }
}

bool MediaTcpClient::creatSocketConnect(uint16_t port)
{
    std::lock_guard<std::mutex> guard(m_connectMutex);
    
    if(m_connetStatus)
    {
        return true;
    }
    
	
	memset(&m_svrSocketInfo, 0, sizeof(m_svrSocketInfo));
	
	m_svrSocketInfo.sin_family = AF_INET;//设置为IP通信
	m_svrSocketInfo.sin_addr.s_addr = inet_addr(m_svrAddr.c_str());//服务器IP地址
	m_svrSocketInfo.sin_port = htons(port); //服务器端口号
	
	//创建客户端套接字 IPv4 tcp
	if((m_clientSockfd = socket(PF_INET, SOCK_STREAM, 0))<0)
	{
		LOG_PrintError("socket error");
		return false;
	}

    m_svrPort = port;
    
	m_connetStatus = true;

	m_threadConnect.start([this](Fdt::Thread *thread){this->connectSocketThread(thread);}); //启动单独线程接收数据

	return true;
}

bool MediaTcpClient::destroySocketConnect(uint16_t port)
{
    std::lock_guard<std::mutex> guard(m_connectMutex);
    if(m_connetStatus && m_clientSockfd > 0)
    {
        m_thread.stop();
        close(m_clientSockfd);
        m_connetStatus = false;

        LOG_PrintInfo("MediaTcpClient destroySocketConnect success,m_svrAddr:%s\n", m_svrAddr.c_str());
    }
    
    return true;
}

void MediaTcpClient::connectSocketThread(Fdt::Thread *thread)
{
    if(m_clientSockfd < 0)
    {
        return;
    }

    while (thread->running())
    {    
        //连接服务器网络地址
    	if(connect(m_clientSockfd, (struct sockaddr*)&m_svrSocketInfo, sizeof(struct sockaddr)) < 0)
    	{
    		//LOG_PrintError("connectSocketThread failed m_svrAddr:%s, errno=%d, errormsg=%s\n", m_svrAddr.c_str(),errno, strerror(errno));
    	}
    	else
    	{
            break;
    	}

    	thread->sleep(3*1000);
	}

	LOG_PrintInfo("connectSocketThread success,m_svrAddr:%s\n", m_svrAddr.c_str());

	CurtainActManager::instance()->cameraInfoUpdate(true, m_svrAddr);
	
	MsgQueueManage::instance(m_svrPort)->startReceiveTherad(); //启动单独线程处理接收的数据

	m_thread.start([this](Fdt::Thread *thread){this->ThreadProc(thread);}); //启动单独线程接收数据

	sendKeepLive();

	m_threadConnect.stop();
}


bool MediaTcpClient::detectConnectIsConnect()
{
    struct tcp_info stTcpInfo;
    int ilen = sizeof(stTcpInfo);

    getsockopt(m_clientSockfd, IPPROTO_TCP, TCP_INFO, &stTcpInfo,(socklen_t *)&ilen);
    if( (stTcpInfo.tcpi_state == TCP_CLOSE_WAIT) && (stTcpInfo.tcpi_state != TCP_ESTABLISHED) ) //发送数据增加是否正常连接判定
    {
        printf("MediaTcpClient  detectClientIsConnect (task-%d)\n",m_clientSockfd);
        return false;
    }

    //printf("vdo_socketTcp  connect (task-%d)\n",m_clientSockfd);
    

    return true;
}

bool MediaTcpClient::keepLiveTimeout()
{
    m_keepLiveTimer.reset();
    
    destroySocketConnect(m_svrPort);
    
    CurtainActManager::instance()->cameraInfoUpdate(false, m_svrAddr);

    //重新建立连接
    creatSocketConnect(m_svrPort);
    
    return true;
}

bool  MediaTcpClient::sendKeepLive()
{
    auto keepLiveTask = [this]
    {
        m_keepLiveTimer.reset();
        sleep(5);        
        m_keepLiveTimer.reset(new Fdt::Timer(5 * 1000, ([this](){return this->keepLiveTimeout();}), nullptr));

        std::string message = "< GET KEEP_LIVE>";//"< GET KEEP_LIVE >";

        sendMessage(message);
    };
    
    thread downloadThread(keepLiveTask);
    downloadThread.detach();

    return true;
}

bool MediaTcpClient::sendMessage(const std::string& strMsg)
{
	if(m_clientSockfd < 0 || !detectConnectIsConnect())
    {
        return false;
    }
    int length = strMsg.size();
	int sentBytes = send(m_clientSockfd, strMsg.c_str(), length, 0);
	if (sentBytes == length)
	{
	    tracef("MediaTcpClient::sendMessage success,m_svrAddr=%s,strMsg=%s\n", m_svrAddr.c_str(),strMsg.c_str());
		return true;
	}

	errorf("MediaTcpClient::sendMessage failed,sentBytes=%d\n", sentBytes);
	return false;
	
}

void MediaTcpClient::ThreadProc(Fdt::Thread *thread)
{
    thread->setPriority(Fdt::PRIORITY_NORMAL, Fdt::POLICY_RR);

    LOG_PrintInfo("MediaTcpClient::ThreadProc enter\n");

    char recvBuf[RECEIVE_LEN];//数据接收缓冲区
    int len = 0;

    int iRet = 0;
    fd_set readset;  
    FD_ZERO(&readset);
    fd_set readfds_temp; //用来备份原集合
    FD_ZERO(&readfds_temp);//清空
    
    FD_SET(m_clientSockfd, &readset);
    struct timeval  tm ;
    tm.tv_sec  = 2;
    tm.tv_usec = 0;
        
    while (thread->running())
    {
        if(!m_connetStatus)
        {
            thread->sleep(100);
            continue;
        } 

        readfds_temp = readset;
        iRet = select(m_clientSockfd + 1 , &readfds_temp, NULL, NULL, &tm );
        if(iRet > 0)
        {
            if(FD_ISSET(m_clientSockfd, &readfds_temp))
            {
                memset(recvBuf, 0, sizeof(recvBuf));

                len = recv(m_clientSockfd, recvBuf, RECEIVE_LEN, 0);
                if (len == -1) 
                {
                    printf("recvfrom fail\r\n");
                }
                else if (len > 0) 
                {
                    recvBuf[len]='\0';		    
        		    printf("MediaTcpClient recv m_svrAddr:%s, buf=%s, Info Length=%d\n", m_svrAddr.c_str(), recvBuf, len); //< REP VIDEO_SPEAKING_SLAVE_DEVICE 1 >

        		    MsgQueueManage::MessagePtr msg(new MsgQueueManage::MessageBuffer(len + 1));
        		    msg->commAddr = m_svrAddr;
        		    msg->commPort = m_svrPort;

                    memcpy(msg->data, recvBuf, len + 1);
                    msg->size = len;

        		    MsgQueueManage::instance(m_svrPort)->SaveToCommQueue(msg);
                }
            }
        }

        thread->sleep(5);        
    }

    LOG_PrintInfo("MediaTcpClient::ThreadProc leave\n");

    return;
}


}

